import rdflib
from rdflib import ConjunctiveGraph, Literal, Namespace, URIRef
from rdflib_endpoint import SparqlEndpoint
from flask import Flask, request, render_template
from rdflib.plugins.sparql import prepareQuery, sparql
from rdflib.plugins.sparql.evalutils import _eval
from SPARQLWrapper import SPARQLWrapper, JSON
from rdflib import Graph


import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk.tag import pos_tag
from nltk.chunk import ne_chunk
import jieba
import jieba.posseg as pseg
import re


app = Flask(__name__)

# 创建一个 RDFLib 图形对象并加载数据
g = ConjunctiveGraph()
g.parse("text.ttl", format="turtle")

#命名空间
ctext = Namespace("https://data.ctext.org/entity/")
claim = Namespace("https://data.ctext.org/claim/")
rdfs = Namespace("http://www.w3.org/2000/01/rdf-schema#")
cprop = Namespace("https://data.ctext.org/property/")
cqual = Namespace("https://data.ctext.org/qualifier/")
cstat = Namespace("https://data.ctext.org/statement/")
date = Namespace("https://data.ctext.org/date/")

#连接字符串，并将长度作为附加的长度变量返回
def custom_concat(query_results, ctx, part, eval_part):
    #两个输入
    argument1 = str(_eval(part.expr.expr[0], eval_part.forget(ctx, _except=part.expr._vars)))
    argument2 = str(_eval(part.expr.expr[1], eval_part.forget(ctx, _except=part.expr._vars)))
    evaluation = []
    scores = []
    #两个结果字符串，一个评估，一个分数
    evaluation.append(argument1 + argument2)
    evaluation.append(argument2 + argument1)
    scores.append(len(argument1 + argument2))
    scores.append(len(argument2 + argument1))
    # 附加函数
    for i, result in enumerate(evaluation):
        query_results.append(eval_part.merge({
            part.var: rdflib.Literal(result),
            #额外的长度变量
            rdflib.term.Variable(part.var + 'Length'): rdflib.Literal(scores[i])
        }))
    return query_results, ctx, part, eval_part
#给定实体最相近的实体
def most_similar(query_results, ctx, part, eval_part):
    similarity_results = [{"mostSimilar": "DRUGBANK:DB00001", "score": 0.42}]

    evaluation = []
    scores = []
    for most_similar in similarity_results:
        evaluation.append(most_similar["mostSimilar"])
        scores.append(most_similar["score"])

    # 结果放进query_results
    for i, result in enumerate(evaluation):
        query_results.append(
            eval_part.merge({part.var: Literal(result), rdflib.term.Variable(part.var + "Score"): Literal(scores[i])})
        )
    return query_results, ctx, part, eval_part


#分出句子中的人名和sparql模板
def names(query):
    # 用户查询语句
    # query = "姜夔作品有哪些"
    # 使用结巴分词进行中文分词
    words = jieba.lcut(query)

    words = pseg.cut(query)  # jieba默认模式
    person_name = None
    for word, flag in words:
        if flag == "nr":
            person_name = word

    print(person_name)
    # 构建SPARQL查询
    qres = prepareQuery(f"""
        PREFIX ctext: <https://data.ctext.org/entity/>
        PREFIX claim: <https://data.ctext.org/claim/>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
        SELECT ?workName
        WHERE {{
            ?person claim:name "{person_name}" .
            ?work claim:creator ?person ;
                  rdfs:label ?workName .
        }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return qres,person_name


#SPARQL查询作品并返回结果
def work(sparql_query):
    qres, personname = names(sparql_query)

    # 执行SPARQL查询
    results = g.query(qres)
    #print(results)
    # 将结果转换为字符串列表
    result_list=list(results)

    result_list = [str(result) for result in results]
    #print("result_list", result_list)
    pattern = r"'(.+)'"
    words = [re.search(pattern, item).group(1) for item in result_list]
    print(words,personname)
    return words,personname


#sparql.setQuery(sparql_query)
#    sparql.setReturnFormat(JSON)
#    results = sparql.query().convert()
#    查询结果
#    era_names = [result['eraName']['value'] for result in results['results']['bindings']]"""



#查询人物生卒年份
def life_died(query):
    # 用户查询语句
    # query = "陈迥的生卒年份"
    # 使用结巴分词进行中文分词
    words = jieba.lcut(query)

    words = pseg.cut(query)  # jieba默认模式
    person_name = None
    for word, flag in words:
        if flag == "nr":
            person_name = word

    #print(person_name)
    # 构建SPARQL查询
    qres = prepareQuery(f"""
        PREFIX ctext: <https://data.ctext.org/entity/>
        PREFIX claim: <https://data.ctext.org/claim/>
        PREFIX cprop: <https://data.ctext.org/property/>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        
        SELECT ?born ?died
        WHERE {{
          ?person claim:name ?name ;
                  claim:born ?born ;
                  claim:died ?died .
          FILTER (regex(?name, "{person_name}"))
        }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return qres, person_name

#查询人物生卒年
def lifespan(query):
    qres, personname = life_died(query)

    # 执行SPARQL查询
    results = g.query(qres)
    for result in results:
        born_year = re.findall(r'\d+', str(result[0]))[0]  #出生年份
        died_year = re.findall(r'\d+', str(result[1]))[0]  #死亡年份
        print(born_year,died_year,personname)

        #lifedie=str(personname) + "生于" + str(born_year)+"年，死于"+str(died_year)+"年"

    return born_year,died_year,personname

#查询维基链接
def wiki(query):
    # 用户查询语句
    # query = "陈迥的更多信息"
    # 使用结巴分词进行中文分词
    words = jieba.lcut(query)

    words = pseg.cut(query)  # jieba默认模式
    person_name = None
    for word, flag in words:
        if flag == "nr":
            person_name = word

    # print(person_name)
    # 构建SPARQL查询
    qres = prepareQuery(f"""
        PREFIX ctext: <https://data.ctext.org/entity/>
        PREFIX claim: <https://data.ctext.org/claim/>
        PREFIX cprop: <https://data.ctext.org/property/>
        
        SELECT ?link
        WHERE {{
                ?person claim:name "{person_name}" ;
                  claim:link-wikipedia_zh ?link .
        }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return qres, person_name

# 查询维基
def wikilink(query):
    qres, personname = wiki(query)

    # 执行SPARQL查询
    results = g.query(qres)
    #转换为列表
    results_list = list(results)
    if results_list:
        #提取链接
        link = results_list[0][0]
    print(link,personname)

    return link,personname

#
#"""wiki_link="有关"+str(personname)+"的更多信息，请查询"+"<a href=\""+str(link)+"\">"+str(personname)+"（维基百科）"+"</a>"
#    else:
#        wiki_link="找不到关于"+str(personname)+"的链接信息""""

# 查询人物的字
def namest(query):
    # 用户查询语句
    # query = "陈迥的更多信息"
    # 使用结巴分词进行中文分词
    words = jieba.lcut(query)

    words = pseg.cut(query)  # jieba默认模式
    person_name = None
    for word, flag in words:
        if flag == "nr":
            person_name = word

    # print(person_name)
    # 构建SPARQL查询
    qres = prepareQuery(f"""
        PREFIX ctext: <https://data.ctext.org/entity/>
        PREFIX claim: <https://data.ctext.org/claim/>
        PREFIX cprop: <https://data.ctext.org/property/>

       SELECT ?namestyle
        WHERE {{
          ?person claim:name "{person_name}" ;
                  claim:name-style ?namestyle .
        }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return qres, person_name

# 查询人物的字
def nickname(query):
    qres, personname = namest(query)

    # 执行SPARQL查询
    results = g.query(qres)
    # 转换为列表
    results_list = list(results)

    nick = results_list[0][0]
    print(nick,personname)

    return nick,personname

#原字

"""if results_list:
        # 提取链接
        nick = results_list[0][0]
        nickn = str(personname) + "的字是：" + str(nick)
    else:
        nickn = "找不到关于" + str(personname) + "的信息"""

#查询人物朝代
def dy(query):
    # 用户查询语句
    # query = "姜夔是哪个朝代的人"
    # 使用结巴分词进行中文分词
    words = jieba.lcut(query)

    words = pseg.cut(query)  # jieba默认模式
    person_name = None
    for word, flag in words:
        if flag == "nr":
            person_name = word

    # print(person_name)
    # 构建SPARQL查询
    qres = prepareQuery(f"""
        PREFIX ctext: <https://data.ctext.org/entity/>
        PREFIX claim: <https://data.ctext.org/claim/>
        PREFIX cprop: <https://data.ctext.org/property/>
        
        SELECT DISTINCT ?dynastyLabel
        WHERE {{
           ?person claim:name "{person_name}" .
           ?person claim:associated-dynasty ?dynasty.
           ?dynasty rdfs:label ?dynastyLabel .
        }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return qres, person_name

# 查询人物的朝代
def pdy(query):
    qres, personname = dy(query)

    # 执行SPARQL查询
    results = g.query(qres)
    # 转换为列表
    results_list = list(results)
    #if results_list:
        # 提取链接
    #    dyna = results_list[0][0]
    #    dyn = str(personname) + "所属的朝代是：" + str(dyna)
    #else:
    #    dyn= "找不到关于" + str(personname) + "的朝代信息"
    dyna = results_list[0][0]
    print(dyna,personname)

    return dyna,personname

#某朝代人物
def dynasty_person(query):
    # query = "宋的人物有哪些"
    words=jieba.lcut(query, cut_all=False)
    keywords = [word for word in words if word != ' ']
    dynastyname=keywords[0]

    qres = prepareQuery(f"""
    PREFIX ctext: <https://data.ctext.org/entity/>
    PREFIX claim: <https://data.ctext.org/claim/>
    PREFIX cprop: <https://data.ctext.org/property/>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

    SELECT DISTINCT ?personName
    WHERE {{
        ?dynasty claim:name "{dynastyname}" .
         ?person claim:associated-dynasty ?dynasty;
                 rdfs:label ?personName .
    }}
    """, initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})

    return qres,dynastyname

def dynasty(sparql_query):
    qres, dynastyname = dynasty_person(sparql_query)

    # 执行SPARQL查询
    results = g.query(qres)
    # print(results)
    # 将结果转换为字符串列表
    result_list = list(results)
    result_list = [str(result) for result in results]
    # print("result_list", result_list)
    pattern = r"'(.+)'"
    words = [re.search(pattern, item).group(1) for item in result_list]

    print(words,dynastyname)

    return words,dynastyname



# 查询所有朝代名称
def generate_sparql_query(question):
    query = prepareQuery(f"""
            PREFIX ctext: <https://data.ctext.org/entity/>
            PREFIX claim: <https://data.ctext.org/claim/>
            PREFIX cprop: <https://data.ctext.org/property/>
            PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

            SELECT DISTINCT ?dynastyName
            WHERE {{
              ?dynasty claim:type "era" ;
                      claim:name ?dynastyName .
            }}""", initNs={"ctext": ctext, "claim": claim, "rdfs": rdfs})
    return query

# 查询朝代
def era(query):
    sparql_query = generate_sparql_query(query)
    # 执行SPARQL查询
    results = g.query(sparql_query)
    result_list = [str(result) for result in results]
    # print("result_list", result_list)
    pattern = r"'(.+)'"
    words = [re.search(pattern, item).group(1) for item in result_list]
    #era_names = "共收录" + str(len(results)) + "个朝代\n" + str(words)
    print(words)

    return words


def other(query):
    res="敬请期待！"
    return res



sparql= SPARQLWrapper("http://localhost:8080/sparql")  # 设置SPARQL端点的URL


@app.route('/')
def index():
    return render_template('index.html')

@app.route('/query', methods=['POST'])



def query():

    sparql_query = request.form['query']
    prompt=None
    born=None
    died=None
    result=None
    personname=""

#√
    if "作品有哪些" in sparql_query:
        result,personname = work(sparql_query)
        prompt=str(personname)+"的作品有："
#√
    elif "生卒年" in sparql_query:
        born,died,personname=lifespan(sparql_query)
        prompt="生卒年："
#√
    elif "更多信息" in sparql_query:
        result,personname=wikilink(sparql_query)
        prompt=str(personname)+"的更多信息，请查询："
#√
    elif "字" in sparql_query:
        result,personname=nickname(sparql_query)
        prompt=str(personname)+"的字是："
#√
    elif "哪个朝代" in sparql_query:
        result,personname = pdy(sparql_query)
        prompt=str(personname)+"所属的朝代是："

    elif "人物有哪些" in sparql_query:
        result,dynastyname= dynasty_person(sparql_query)
        prompt=str(dynastyname) + "的人物有："
#√
    elif "所有朝代名称" in sparql_query:
        result=era(sparql_query)
        prompt="共收录"+str(len(result))+"个朝代："
    else:
        # 执行其他操作的函数
        result = other(sparql_query)
    print(result)
    print(prompt)
    print(personname)
    print(born)
    print(died)
    return render_template('index.html', result=result,prompt=prompt,personname=personname,born=born,died=died)
"""


    user_input = request.form['query']
    
    # 解析用户输入的自然语言查询
    sparql_query = pwork(user_input)
    sparql.setQuery(sparql_query)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()
    return render_template('index.html', result=results)

"""


if __name__ == '__main__':
    # 启动 SPARQL 端点服务
    endpoint = SparqlEndpoint(
        graph=g,
        functions={
            "https://w3id.org/um/openpredict/most_similar": most_similar,
            "https://w3id.org/um/sparql-functions/custom_concat": custom_concat,
        },
        title="SPARQL endpoint for RDFLib graph",
        description="A simple SPARQL endpoint for RDFLib graph",
        version="1.0",
        path="/sparql",
        public_url="http://localhost:8080/sparql",
        cors_enabled=True
    )
    app.run(host='localhost', port=8080)
